import React, {PureComponent} from 'react';
import interact from 'interactjs';

/**
 * SliderVerificationDialog
 */
export default class SliderVerificationDialog extends PureComponent {
  static defaultProps = {
    onClose: () => {
    },
    onError: () => {
    },
    onComplete: () => {
    }
  };

  constructor(props) {
    super(props);
    this.sliderBoxWidth = 50;
    this.containerWidth = 400;
    this.containerHeight = 300;
    this.containerPadding = 15;
    this.contentWidth = this.containerWidth - this.containerPadding * 2;
    this.contentHeight = 220;
    this.availbelLeftPos = this.generateAvailablePos(this.contentWidth - this.sliderBoxWidth)
      .filter(v => v > this.sliderBoxWidth * 2);
    this.availbelTopPos = this.generateAvailablePos(this.contentHeight - this.sliderBoxWidth);
    this.state = {
      showCheckIcon: false,
      showTip: false,
      ...this.randomPosition(),
      ...this.initDomId()
    };
  }

  uuid = () => {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
      const r = Math.random() * 16 | 0;
      const v = c === 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
    });
  };

  initDomId = () => {
    return {
      sliderId: `slider-${this.uuid()}`,
      frontBoxId: `front-box-${this.uuid()}`,
      nedBoxId: `end-box-${this.uuid()}`
    };
  };

  generateAvailablePos = (len, blank = 20) => {
    return len ? Array(len).fill('').map((v, i) => i % blank === 0 && i > 0 && i).filter(Boolean) : [];
  };

  componentDidMount() {
    this.setDragEvent();
  }

  componentDidUpdate() {
    this.setDragEvent();
  }

  randomPosition = () => {
    const randomIndex = (max) => Math.floor(Math.random() * (max + 1));
    const leftIndex = randomIndex(this.availbelLeftPos.length);
    const topIndex = randomIndex(this.availbelTopPos.length);
    return {
      endBoxLeft: this.availbelLeftPos[leftIndex] || this.contentWidth - this.sliderBoxWidth,
      endBoxTop: this.availbelTopPos[topIndex] || this.sliderBoxWidth
    };
  };

  setDragEvent = () => {
    const {sliderId, frontBoxId, nedBoxId} = this.state;
    const frontBox = document.querySelector(`#${frontBoxId}`);
    const endBox = document.querySelector(`#${nedBoxId}`);
    const slider = document.querySelector(`#${sliderId}`);
    if (!frontBox || !endBox || !slider) return;
    const parseFloatFix = (v) => parseFloat(parseFloat(v || 0).toFixed(4));
    interact(slider).draggable({
      onstart: () => {
        this.setState({showTip: false, showCheckIcon: false});
      },
      onmove: (e) => {
        const target = e.target;
        const x = parseFloatFix(target.getAttribute('data-x')) + e.dx;
        if (x < 0 || x > 320) return;
        target.style.webkitTransform = target.style.transform = `translateX(${x}px)`;
        frontBox.style.webkitTransform = frontBox.style.transform = `translateX(${x}px)`;
        target.setAttribute('data-x', x);
        frontBox.setAttribute('data-x', x);
      },
      onend: (e) => {
        const frontLeft = parseFloatFix(frontBox.style.transform.match(/[^\\(\\)]+(?=\))/g)[0]);
        const endLeft = parseFloatFix(endBox.style.left);
        const endTop = parseFloatFix(endBox.style.top);
        if (Math.abs(frontLeft - endLeft) < 2) {
          this.setState({showCheckIcon: true, showTip: false});
          setTimeout(() => {
            this.props.onComplete && this.props.onComplete({
              key: Date.now(),
              left: frontLeft,
              top: endTop
            });
          }, 1000);
        } else {
          frontBox.style.webkitTransform = frontBox.style.transform = 'translateX(0px)';
          slider.style.webkitTransform = slider.style.transform = 'translateX(0px)';
          slider.setAttribute('data-x', 0);
          frontBox.setAttribute('data-x', 0);
          this.setState({
            showTip: true,
            ...this.randomPosition(),
            ...this.initDomId()
          });
          this.props.onError && this.props.onError({
            key: Date.now(),
            left: frontLeft,
            top: endTop
          });
        }
      }
    });
  };

  createCssObj = () => {
    return {
      bgStyle: {
        position: 'fixed',
        left: 0,
        top: 0,
        zIndex: 10000,
        width: '100vw',
        height: '100vh',
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: 'rgba(0, 0, 0, 0.6)'
      },
      containerStyle: {
        position: 'relative',
        width: this.containerWidth,
        height: this.containerHeight,
        borderRadius: 5,
        display: 'flex',
        alignItems: 'center',
        padding: this.containerPadding,
        flexDirection: 'column',
        backgroundColor: '#fff'
      },
      checkStyle: {
        position: 'absolute',
        right: 20,
        bottom: 25
      },
      contentStyle: {
        position: 'relative',
        width: this.contentWidth,
        height: this.contentHeight
      },
      contentBgStyle: {
        position: 'absolute',
        left: 0,
        top: 0,
        width: '100%',
        height: this.contentHeight,
        filter: 'blur(2px)',
        background: 'url("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3268679811,3433201367&fm=26&gp=0.jpg") no-repeat 100% 100%'
      },
      operationBar: {
        position: 'absolute',
        left: this.containerPadding,
        bottom: 20,
        width: this.contentWidth,
        height: '30px',
        borderRadius: 5,
        backgroundColor: '#eee',
        lineHeight: '30px',
        textAlign: 'center',
        letterSpacing: '2px'
      },
      sliderStyle: {
        position: 'absolute',
        left: this.containerPadding,
        bottom: 18,
        backgroundColor: '#fff',
        display: 'block',
        width: 40,
        height: 35,
        fontSize: '30px',
        lineHeight: '35px',
        textAlign: 'center',
        borderRadius: 5,
        cursor: 'pointer',
        boxShadow: '0 0 10px rgba(0, 0, 0, .3)'
      },
      frontSliderStyle: {
        position: 'absolute',
        left: 0,
        top: 20,
        width: this.sliderBoxWidth,
        height: this.sliderBoxWidth,
        borderRadius: '3px',
        backgroundColor: '#d9d9d9',
        boxShadow: '0 0 10px rgba(0, 0, 0, .6)'
      },
      endSliderStyle: {
        position: 'absolute',
        left: 250,
        top: 20,
        borderRadius: '3px',
        width: this.sliderBoxWidth,
        height: this.sliderBoxWidth,
        backgroundColor: 'rgba(0, 0, 0, 0.7)',
        boxShadow: '0 0 10px rgba(0, 0, 0, .6)'
      },
      tipStyle: {
        position: 'absolute',
        left: '0px',
        top: '0',
        color: 'rgb(255, 195, 0)',
        width: '100%',
        textAlign: 'center',
        backgroundColor: 'rgba(0, 0, 0, 0.4)',
        margin: 0,
        fontSize: '12px'
      },
      closeStyle: {
        position: 'absolute',
        right: -13,
        top: -13,
        backgroundColor: '#fff',
        width: 30,
        height: 30,
        borderRadius: 15,
        fontSize: 18,
        lineHeight: '30px',
        textAlign: 'center',
        cursor: 'pointer'
      }
    };
  };

  render() {
    const {containerStyle, bgStyle, closeStyle, contentStyle, contentBgStyle, sliderStyle, operationBar, frontSliderStyle, endSliderStyle, tipStyle, checkStyle} = this.createCssObj();
    const {sliderId, frontBoxId, nedBoxId, endBoxLeft, endBoxTop, showTip, showCheckIcon} = this.state;
    return (
      <div style={bgStyle}>
        <div style={containerStyle}>
          <span style={closeStyle} onClick={this.props.onClose}>✕</span>
          <div style={contentStyle}>
            <div style={contentBgStyle}/>
            <div id={frontBoxId} style={{...frontSliderStyle, top: endBoxTop}}/>
            <div id={nedBoxId} style={{...endSliderStyle, top: endBoxTop, left: endBoxLeft}}/>
            {showTip && <p style={tipStyle}>验证不成功，请重试！</p>}
          </div>
          <div style={operationBar}>请向右拖动滑块完成安全验证</div>
          <span id={sliderId} style={sliderStyle}>≡</span>
          {showCheckIcon &&
          <svg
            style={checkStyle}
            viewBox="64 64 896 896"
            data-icon="check"
            width="20"
            height="20"
            fill="#52c41a"
            aria-hidden="true">
            <path
              d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
          </svg>}
        </div>
      </div>
    );
  }
}
